package com.lj.demo.springbootshirojwt.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.List;

/**
 * Title: JWT工具类
 * Description:
 * Date: 2019年04月02日 9:36
 * @author lvjie@hiynn.com
 * @version 1.0
 * Significant Modify：
 * Date                  Author                 Content
 * =================================================================
 * 2019年04月02日         lvjie@hiynn.com         创建文件,实现基本功能
 * =================================================================
 */
public class JWTUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(JWTUtil.class);

    private JWTUtil(){

    }

    /**
     * 校验token是否正确  参考sign生成规则
     * @param token 密钥
     * @param userName 用户名
     * @param secret 用户密码
     * @return 是否正确
     */
    public static boolean verify(String token, String userName,String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(Constants.TOKEN_SECRET+secret);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim(Constants.TOKEN_USER_NAME, userName)
                    .build();
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            LOGGER.error("校验token失败：",e);
            return false;
        }
    }

    /**
     * 生成签名,包含过期时间，包含角色及权限信息
     * @param secret 秘钥和密码相关  保证修改后之前的签名失效
     * @return 加密的token
     */
    public static boolean verify(String token, String secret) {
        try {
            try {
                Algorithm algorithm = Algorithm.HMAC256(Constants.TOKEN_SECRET+secret);
                String userName = JWTUtil.getUserName(token);
                List<String> permissions = JWTUtil.getPermissions(token);
                List<String> roles = JWTUtil.getRoles(token);
                JWTVerifier verifier = JWT.require(algorithm)
                        .withClaim(Constants.TOKEN_USER_NAME, userName)
                        .withArrayClaim(Constants.TOKEN_USER_ROLE, roles.toArray(new String[roles.size()]))
                        .withArrayClaim(Constants.TOKEN_USER_PERMISSION,permissions.toArray(new String[permissions.size()]))
                        .build();
                verifier.verify(token);
                return true;
            } catch (Exception e) {
                LOGGER.error("校验token失败：",e);
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获得token中的信息
     * @return token中包含的用户名
     */
    public static String getUserName(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(Constants.TOKEN_USER_NAME).asString();
        } catch (Exception e) {
            LOGGER.error("获取token中的用户名失败：",e);
            return null;
        }
    }

    /**
     * 获得token中的信息
     * @return token中包含的过期时间戳
     */
    public static Long getExpireTime(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            //exp 为官方定义字段  所有jwtToken都有 详情参考jwt生成规则
            return jwt.getClaim("exp").asLong();
        } catch (Exception e) {
            LOGGER.error("获取token中的过期时间戳失败：",e);
            return null;
        }
    }

    /**
     * 获得token中的信息
     * @return token中包含的用户角色信息
     */
    public static List<String> getRoles(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(Constants.TOKEN_USER_ROLE).asList(String.class);
        } catch (Exception e) {
            LOGGER.error("获取token中的用户角色信息失败：",e);
            return null;
        }
    }

    /**
     * 获得token中的信息
     * @return token中包含的用户权限信息
     */
    public static List<String> getPermissions(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(Constants.TOKEN_USER_PERMISSION).asList(String.class);
        } catch (Exception e) {
            LOGGER.error("获取token中的用户权限信息失败：",e);
            return null;
        }
    }

    /**
     * 生成签名,包含过期时间
     * @param userName 用户名
     * @param secret 秘钥与密码有关  保证修改后之前的签名失效
     * @param expireTime 过期时间
     * @return 加密的token
     */
    public static String sign(String userName,String secret,long expireTime) {
        try {
            Date date = new Date(System.currentTimeMillis()+expireTime);
            Algorithm algorithm = Algorithm.HMAC256(Constants.TOKEN_SECRET+secret);
            return JWT.create()
                    .withClaim(Constants.TOKEN_USER_NAME, userName)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            LOGGER.error("生成签名失败：",e);
            return null;
        }
    }

    /**
     * 生成签名,包含过期时间，包含角色及权限信息
     * @param userName 用户名
     * @param secret 秘钥和密码相关  保证修改后之前的签名失效
     * @param expireTime 过期时间
     * @param roles 角色信息  该用户的所有角色
     * @param permissions 权限信息  该用户拥有的所有权限
     * @return 加密的token
     */
    public static String sign(String userName, String secret, long expireTime, List<String> roles,List<String> permissions) {
        try {
            Date date = new Date(System.currentTimeMillis()+expireTime);
            Algorithm algorithm = Algorithm.HMAC256(Constants.TOKEN_SECRET+secret);
            return JWT.create()
                    .withClaim(Constants.TOKEN_USER_NAME, userName)
                    .withArrayClaim(Constants.TOKEN_USER_ROLE, roles.toArray(new String[roles.size()]))
                    .withArrayClaim(Constants.TOKEN_USER_PERMISSION,permissions.toArray(new String[permissions.size()]))
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            LOGGER.error("生成签名失败：",e);
            return null;
        }
    }
}
